home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d18
/
tpschk11.arc
/
SELFCHK.PAS
< prev
Wrap
Pascal/Delphi Source File
|
1991-04-28
|
9KB
|
213 lines
Unit SelfChk;
{$I-}
(* *)
(* The SelfChk Unit, Release 1.1, 02/05/1990. *)
(* *)
(* This UNIT for Borland's Turbo Pascal version 4.0+ provides your *)
(* programs with a means of checking themselves for changes at run- *)
(* time as both an anti-viral and anti-hack measure. *)
(* *)
(* This UNIT is (C) 1990 by Michael S. Durkin and is distributed as *)
(* SHAREWARE. Registration information is within the documentation, *)
(* and is requested if you use The SelfChk Unit in your programs. *)
(* You may NOT distribute modified source code. Do NOT modify this *)
(* or any other copyright notice. *)
(* *)
(* Please forward any examples/suggestions for improvement or bug *)
(* reports to me for consideration or fixes. *)
(* *)
(* Mike Durkin The TeleSoft RBBS-PC *)
(* P.O. Box 1021 Data: (415) 969-8238 *)
(* Mt. View, CA Four Lines (CAPAL) *)
(* 94042-1021 FidoNet: (1:143/204) *)
(* *)
(* Place SelfChk in your Uses statement. Execute SCHKINST against *)
(* your executable after compilation. Within your program use the *)
(* DoSelfChk procedure to generate the CRC. SelfChkResult is bit *)
(* mapped as noted below with the result of the SelfChk. Or, call *)
(* ChkIntegrity (as an example) to check your executable and it'll *)
(* take appropriate action. The low order Word of the FileSize of *)
(* your program is used as an initial seed value for the 16 bit CRC *)
(* routine (rather than $0000) for additional security. *)
(* *)
(* The SelfChk Unit will add, typically from 0.8 to 1.8k to your *)
(* programs filesize depending on how many of the standard procedures *)
(* this unit uses, that your program already used. Memory usage *)
(* depends in part on the size of the disk buffer you choose. I *)
(* recommend sharing the disk buffer with your main program to cut *)
(* down on memory usage. *)
(* *)
(* And a final note: A condition of your use of The SelfChk Unit is *)
(* that you don't make fun of my programming! It may be awful, but *)
(* it gets the job done, and with a minimum of resources and time. *)
(* If there is any part of this unit that confuses you, I'll be glad *)
(* to clear it up. *)
(* *)
INTERFACE
Uses Dos;
Const
SelfChkResult : Byte = 0; { Bit Mapped result after call to DoSelfChk (bit) }
{ 0 := SelfChk appears fine - }
{ 1 := IOError - couldn't check 0 }
{ 2 := 16bit CRC (w/filesize seed) failed 1 }
(* Note: The following 4 constants must remain at minimum in this order *)
(* to ensure that SCHKINST can find them during data installation and *)
(* change 'file_crc' to reflect the actual CRC (seed=lo_word(filesize)). *)
data_ofs : LongInt = $FFFFFFFF; { OffSet to DATA installed by SCHKINST }
file_crc : Word = $FFFF ; { crc of exec installed by SCHKINST }
crc_ccitt : Word = $0000 ; { runtime generation vs. file_crc }
schk_sign : LongInt = $4B484353; { verification for SCHKINST. Ensures that }
{ SCHKINST is looking at the right data }
Var { Share these with your main program, if you like, just don't }
{ call a procedure from this unit if you need the value of }
{ these variables to stay the same. }
disk_buf : Array[1..2048] of Byte; { disk buffer, ok to change size }
table_ccitt : Array [0..255] of Word;
f : File;
counter, result,
counter2 : Integer;
bytesCRCed : LongInt;
exec_fname : String; { initiliazed to the executables drive/path/filename }
Procedure DoSelfChk; { Compute seeded CRC and set SelfChkResult. }
Procedure ChkIntegrity; { Calls DoSelfChk, examines SelfChkResult, and acts }
{ accordingly. Use this or write your own. }
Procedure UpdSelfChkData;
{ Computes CRC and installs the value into itself. }
{ If your program updates itself, then call this }
{ procedure after you do your update to update the }
{ SelfChk CRC data. Note: Minimal error checking }
{ is done. Please see the Documentation for special }
{ considerations if you use this procedure. It is }
{ also expected that you modify bytes and/or append }
{ to the file only, so 'data_ofs' should not change. }
Procedure Crc_gen( Var s; length : Integer);
{ Generally NOT called by the user. It's placed here }
{ for use by SCHKINST. If you do wish to generate }
{ the CRC of a buffer, set crc_ccitt := 0, and result}
{ to the length of the buffer. Then call this }
{ procedure as crc_gen(buf_name, length_buf); The }
{ CRC of the buffer is placed in crc_ccitt. For a }
{ file, read the next block, and leave crc_ccitt set }
{ at the CRC of the previous block. }
IMPLEMENTATION
{$I crc_gen.inc}
Procedure DoSelfChk;
Begin { Self Check code. }
{$I-}
FileMode := 0; { ReadOnly Mode }
Assign(f,exec_fname);
Reset(f,1);
If IOResult <> 0 Then Begin
SelfChkResult := SelfChkResult OR $01;
Exit;
End;
(* Compute the 16 bit CRC using the low order word of *)
(* the programs FileSize as an initial seed value. *)
crc_ccitt := FileSize(f);
bytesCRCed := 0;
REPEAT
BlockRead(f,disk_buf,SizeOf(disk_buf),result);
(* The next IF..THEN restores the 6 bytes which were altered by SCHKINST *)
(* during data installation to the value ($FF) SCHKINST saw them as *)
(* when it computed the CRC. This is necessary, and does NOT sacrifice *)
(* the integrity of the self check. Any byte(s)/bit(s) changed will *)
(* still generate a bad self check result. *)
If ((data_ofs OR (data_ofs+5)) >= bytesCRCed) AND ((data_ofs OR (data_ofs+5)) <= (bytesCRCed+result)) Then
For counter := 1 to result Do
If ((data_ofs+1) <= (bytesCRCed + counter)) AND
((bytesCRCed + counter) <= (data_ofs+6)) Then disk_buf[counter] := $FF;
crc_gen(disk_buf,result);
bytesCRCed := bytesCRCed + result;
UNTIL Eof(f);
Close(f);
(* Compare the runtime CRC computation with the CRC installed by SCHKINST *)
(* If the two don't match, set the result bit for a bad self check. *)
If (crc_ccitt <> file_crc) Then SelfChkResult := SelfChkResult OR $04;
FileMode := 2; { Read/Write Mode }
End; { Procedure }
Procedure ChkIntegrity;
Begin
DoSelfChk;
If (SelfChkResult AND $01) = $01 Then WriteLn(' Note: I/O Error during CRC SelfChk!');
If SelfChkResult > 1 Then Begin
WriteLn(#7,'WARNING: ',exec_fname,' fails CRC SelfChk!',#7);
Halt;
End;
End; { Procedure ChkIntegrity }
Procedure UpdSelfChkData;
Var
fattr : Word;
Begin
DoSelfChk;
Assign(f,exec_fname);
GetFAttr(f,fattr);
SetFAttr(f,$00);
Reset(f,1);
Seek(f,data_ofs+4);
BlockWrite(f,crc_ccitt,2);
SetFAttr(f,fattr);
Close(f);
End; { Procedure UpdSelfChkData }
{$I+}
Begin { Unit Init Code }
exec_fname := ParamStr(0);
(* build the crc table at runtime - saves approx. *)
(* 400 bytes in the .EXE w/ minimal runtime overhead. *)
(* Modified from the Public Domain program - FILETEST *)
For counter := 0 to 255 Do
Begin
result := counter;
For counter2 := 1 to 8 Do
Begin
If (result and 1) = 1
then result := (result shr 1) xor $8404 { $8404 = CCITT polynomial }
else result := result shr 1;
End;
table_ccitt[counter] := result;
End
End. { of Unit }